package com.yhk.array;

import java.util.NoSuchElementException;

/**
 * @version 1.0
 * @Author moresuo
 * @Date 2024/10/7 9:08
 * @注释 动态数组
 */
public class MyArrayList<E> {
    //存储元素的数组
    private E[] data;
    //记录当前元素个数
    private int size;
    //默认初始容量
    private static final int INIT_CAP=1;

    public MyArrayList(){
        this(INIT_CAP);
    }

    public MyArrayList(int initCapacity) {
        data = (E[]) new Object[initCapacity];
        size=0;
    }


    /**
     * 添加元素到末尾
     * @param e 元素
     */
    public void addLast(E e){
        //首先判断数组容量是否已满
        int cap= data.length;
        //如果数组容量已满则进行扩容
        if (cap == size) {
            resize(2 * cap);
        }
        //将元素添加到size索引的位置
        data[size]=e;
        //容量加一
        size++;
    }

    /**
     * 扩容
     * @param newCap 新容量
     */
    private void resize(int newCap) {
        //创建一个新容量的数组
        E[] temp = (E[]) new Object[newCap];
        //将原数组的数据拷贝到新数组当中
        for (int i=0;i<size;i++){
            temp[i] = data[i];
        }
        //将原数组引用指向新数组
        data=temp;
    }

    /**
     * 添加元素到指定下标
     * @param index 索引
     * @param e 元素
     */
    public void add(int index,E e){
        //判断索引是否越界
        checkPositionIndex(index);
        //查看数组容量是否已满
        int cap=data.length;
        //如果容量已满就将数组进行扩容
        if (cap == size) {
            resize(2 * cap);
        }
        //移动数组元素位置腾位置
        for (int i = size; i > index; i--) {
            data[i] = data[i - 1];
        }
        //插入元素
        data[index]=e;
        //容量增加
        size++;
    }

    /**
     * 添加元素到首部
     * @param e 元素
     */
    public void addFirst(E e){
        add(0, e);
    }

    /**
     * 删除最后一个元素
     * @return 删除的元素
     */
    public E removeLast() {
        //判断数组中是否有元素
        if (size == 0) {
            throw new NoSuchElementException();
        }
        //数组扩缩容，如果当前元素个数等于总容量的1/4,则将容量减半
        int cap= data.length;
        if (size == cap / 4) {
            resize(cap / 2);
        }
        //将数组最后一个元素置为空
        E deleteVal = data[size - 1];
        data[size-1]=null;
        //容量减一
        size--;
        //返回删除的元素
        return deleteVal;
    }

    /**
     * 根据索引删除元素
     * @param index 索引
     * @return 删除的元素
     */
    public E remove(int index) {
        //判断数组中是否存在元素
        if(size==0){
            throw new NoSuchElementException();
        }
        //检测索引是否越界
        checkElementIndex(index);
        //判断是否需要进行扩缩容
        int cap= data.length;
        if (size == cap / 4) {
            resize(cap / 2);
        }
        //元素前置
        E deleteVal = data[index];
        for (int i = index; i < size - 1; i++) {
            data[i] = data[i + 1];
        }
        //将末尾元素置为空
        data[size-1]=null;
        //元素个数减一
        size--;
        //返回删除的元素
        return deleteVal;
    }

    /**
     * 删除首部元素
     * @return 删除的元素
     */
    public E removeFirst(){
        return remove(0);
    }

    /**
     * 根据索引查询元素
     * @param index 索引
     * @return 查询元素
     */
    public E get(int index) {
        //判断索引是否越界
        checkElementIndex(index);
        return data[index];
    }

    /**
     * 根据索引修改元素
     * @param index 索引
     * @param e 元素
     * @return 修改之前的元素
     */
    public E set(int index, E e) {
        //判断索引是否越界
        checkElementIndex(index);
        //修改元素
        E oldVal = data[index];
        data[index]=e;
        return oldVal;
    }

    /**
     * 返回元素个数
     * @return 元素个数
     */
    public int size(){
        return this.size;
    }

    /**
     * 是否为空
     */
    public boolean isEmpty() {
        return size == 0;
    }

    private void checkElementIndex(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("index：" + index + ",size:" + size);
        }
    }

    /**
     * 判断索引是否越界
     * @param index 索引
     */
    private void checkPositionIndex(int index) {
        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException("index：" + index + ",size:" + size);
        }
    }

    public static void main(String[] args) {
        //初始化容量
        MyArrayList<Integer> myArrayList = new MyArrayList<>(3);
        //添加元素
        for (int i = 0; i < 5; i++) {
            myArrayList.addLast(i);
        }
        for (int i = 0; i < myArrayList.size; i++) {
            System.out.println(myArrayList.get(i));
        }
        myArrayList.remove(3);
        myArrayList.add(1, 9);
        myArrayList.addFirst(100);
        myArrayList.removeLast();
        System.out.println("================");
        for (int i = 0; i < myArrayList.size; i++) {
            System.out.println(myArrayList.get(i));
        }
    }
}
